package com.cinema.service;

import com.cinema.dao.MovieDao;
import com.cinema.dao.ScheduleDao;
import com.cinema.dao.TicketDao;
import com.cinema.dao.impl.MovieDaoImpl;
import com.cinema.dao.impl.ScheduleDaoImpl;
import com.cinema.dao.impl.TicketDaoImpl;
import com.cinema.model.Movie;
import com.cinema.model.Schedule;
import com.cinema.model.Ticket;
import com.cinema.util.LogUtil;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 排片服务类
 * 处理排片相关的业务逻辑
 */
public class ScheduleService {
    private final ScheduleDao scheduleDao;
    private final MovieDao movieDao;
    private final TicketDao ticketDao;

    // 预设的放映厅
    private static final String[] CINEMA_HALLS = {"1号厅", "2号厅", "3号厅", "4号厅", "5号厅"};
    // 黄金时段定义
    private static final LocalTime PRIME_START = LocalTime.of(19, 0); // 晚上7点
    private static final LocalTime PRIME_END = LocalTime.of(22, 0);   // 晚上10点

    public ScheduleService() {
        this.scheduleDao = new ScheduleDaoImpl();
        this.movieDao = new MovieDaoImpl();
        this.ticketDao = new TicketDaoImpl();
    }

    /**
     * 添加场次
     */
    public boolean addSchedule(String movieId, String cinemaHall, LocalDateTime showTime, double price, int rows, int cols) {
        // 验证电影是否存在
        Optional<Movie> movieOpt = movieDao.findById(movieId);
        if (!movieOpt.isPresent()) {
            return false;
        }

        Movie movie = movieOpt.get();
        
        // 检查时间冲突
        if (scheduleDao.hasTimeConflict(cinemaHall, showTime, movie.getDuration())) {
            return false;
        }

        // 检查是否提前超过一周安排
        if (showTime.isAfter(LocalDateTime.now().plusWeeks(1))) {
            return false;
        }

        String scheduleId = UUID.randomUUID().toString();
        Schedule schedule = new Schedule(scheduleId, movieId, cinemaHall, showTime, price, rows, cols);
        return scheduleDao.save(schedule);
    }

    /**
     * 修改场次
     */
    public boolean updateSchedule(String operator, String scheduleId, String newMovieId, LocalDateTime newShowTime, double newPrice) {
        Optional<Schedule> scheduleOpt = scheduleDao.findById(scheduleId);
        if (!scheduleOpt.isPresent()) {
            return false;
        }

        // 检查是否有售出的票
        List<Ticket> tickets = ticketDao.findByScheduleId(scheduleId);
        if (!tickets.isEmpty()) {
            return false; // 有售出票的场次不能修改
        }

        Schedule schedule = scheduleOpt.get();
        String originalMovieTitle = getMovieTitle(schedule.getMovieId());
        String newMovieTitle = getMovieTitle(newMovieId);

        schedule.setMovieId(newMovieId);
        schedule.setShowTime(newShowTime);
        schedule.setPrice(newPrice);

        boolean success = scheduleDao.update(schedule);
        if (success) {
            LogUtil.logScheduleManagement(operator, "修改", 
                String.format("场次时间：%s，原片名：%s，修改后片名：%s", 
                    schedule.getShowTime(), originalMovieTitle, newMovieTitle));
        }
        return success;
    }

    /**
     * 删除场次
     */
    public boolean deleteSchedule(String operator, String scheduleId) {
        Optional<Schedule> scheduleOpt = scheduleDao.findById(scheduleId);
        if (!scheduleOpt.isPresent()) {
            return false;
        }

        // 检查是否有售出的票
        List<Ticket> tickets = ticketDao.findByScheduleId(scheduleId);
        if (!tickets.isEmpty()) {
            return false; // 有售出票的场次不能删除
        }

        Schedule schedule = scheduleOpt.get();
        String movieTitle = getMovieTitle(schedule.getMovieId());
        
        boolean success = scheduleDao.deleteById(scheduleId);
        if (success) {
            LogUtil.logScheduleManagement(operator, "删除", 
                String.format("场次时间：%s，片名：%s", schedule.getShowTime(), movieTitle));
        }
        return success;
    }

    /**
     * 自动排片功能
     */
    public List<Schedule> autoSchedule(LocalDateTime startDate, LocalDateTime endDate) {
        List<Schedule> newSchedules = new ArrayList<>();
        List<Movie> movies = movieDao.findAllShowing();
        
        if (movies.isEmpty()) {
            return newSchedules;
        }

        // 按评分排序，评分高的优先安排黄金时段
        movies.sort((m1, m2) -> Double.compare(m2.getRating(), m1.getRating()));

        LocalDateTime current = startDate;
        while (current.isBefore(endDate)) {
            for (String hall : CINEMA_HALLS) {
                LocalDateTime hallTime = current.withHour(10).withMinute(0); // 从上午10点开始
                
                for (Movie movie : movies) {
                    if (hallTime.plusMinutes(movie.getDuration() + 30).isAfter(current.withHour(23))) {
                        break; // 当天排不下了
                    }

                    // 高评分电影安排在黄金时段
                    if (movie.getRating() >= 8.0 && isPrimeTime(hallTime.toLocalTime())) {
                        double price = calculatePrice(movie, hallTime, true);
                        String scheduleId = UUID.randomUUID().toString();
                        Schedule schedule = new Schedule(scheduleId, movie.getMovieId(), hall, hallTime, price, 10, 12);
                        newSchedules.add(schedule);
                        scheduleDao.save(schedule);
                        
                        hallTime = hallTime.plusMinutes(movie.getDuration() + 30); // 间隔30分钟
                    } else if (!isPrimeTime(hallTime.toLocalTime())) {
                        double price = calculatePrice(movie, hallTime, false);
                        String scheduleId = UUID.randomUUID().toString();
                        Schedule schedule = new Schedule(scheduleId, movie.getMovieId(), hall, hallTime, price, 10, 12);
                        newSchedules.add(schedule);
                        scheduleDao.save(schedule);
                        
                        hallTime = hallTime.plusMinutes(movie.getDuration() + 30);
                    }
                }
            }
            current = current.plusDays(1);
        }

        return newSchedules;
    }

    /**
     * 获取指定日期范围的场次
     */
    public List<Schedule> getSchedulesByDateRange(LocalDateTime startDate, LocalDateTime endDate) {
        return scheduleDao.findByDateRange(startDate, endDate);
    }

    /**
     * 获取当日场次
     */
    public List<Schedule> getTodaySchedules() {
        LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        LocalDateTime tomorrow = today.plusDays(1);
        return scheduleDao.findByDateRange(today, tomorrow);
    }

    /**
     * 获取近3日场次
     */
    public List<Schedule> getThreeDaysSchedules() {
        LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        LocalDateTime threeDaysLater = today.plusDays(3);
        return scheduleDao.findByDateRange(today, threeDaysLater);
    }

    /**
     * 获取近一周场次
     */
    public List<Schedule> getWeekSchedules() {
        LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        LocalDateTime oneWeekLater = today.plusWeeks(1);
        return scheduleDao.findByDateRange(today, oneWeekLater);
    }

    /**
     * 根据电影查找场次
     */
    public List<Schedule> getSchedulesByMovie(String movieId) {
        return scheduleDao.findByMovieId(movieId);
    }

    /**
     * 根据ID查找场次
     */
    public Optional<Schedule> findScheduleById(String scheduleId) {
        return scheduleDao.findById(scheduleId);
    }

    /**
     * 获取所有场次
     */
    public List<Schedule> getAllSchedules() {
        return scheduleDao.findAll();
    }

    /**
     * 获取电影标题
     */
    private String getMovieTitle(String movieId) {
        Optional<Movie> movieOpt = movieDao.findById(movieId);
        return movieOpt.map(Movie::getTitle).orElse("未知电影");
    }

    /**
     * 判断是否为黄金时段
     */
    private boolean isPrimeTime(LocalTime time) {
        return !time.isBefore(PRIME_START) && !time.isAfter(PRIME_END);
    }

    /**
     * 计算票价
     */
    private double calculatePrice(Movie movie, LocalDateTime showTime, boolean isPrime) {
        double basePrice = 35.0; // 基础票价
        
        // 根据电影评分调整价格
        if (movie.getRating() >= 9.0) {
            basePrice += 15.0;
        } else if (movie.getRating() >= 8.0) {
            basePrice += 10.0;
        } else if (movie.getRating() >= 7.0) {
            basePrice += 5.0;
        }

        // 黄金时段加价
        if (isPrime) {
            basePrice += 10.0;
        }

        // 早场优惠（上午10点场次打9折）
        if (showTime.getHour() == 10) {
            basePrice *= 0.9;
        }

        return Math.round(basePrice * 100.0) / 100.0; // 保留两位小数
    }

    /**
     * 检查场次是否存在
     */
    public boolean existsById(String scheduleId) {
        return scheduleDao.existsById(scheduleId);
    }

    /**
     * 获取可用的放映厅列表
     */
    public String[] getAvailableCinemaHalls() {
        return CINEMA_HALLS.clone();
    }
}